package com.asen.commons.core.jdbc.dao;

import com.asen.commons.core.jdbc.Jdbc;
import com.asen.commons.core.jdbc.builder.mysql.DeleteBuilder;
import com.asen.commons.core.jdbc.builder.mysql.InsertBuilder;
import com.asen.commons.core.jdbc.builder.mysql.QueryBuilder;
import com.asen.commons.core.jdbc.builder.mysql.UpdateBuilder;
import com.asen.commons.core.jdbc.factory.JdbcFactory;
import com.asen.commons.core.jdbc.param.SqlContext;
import com.asen.commons.core.jdbc.result.BaseResultSetExtractor;
import com.asen.commons.core.meta.dao.Condition;
import com.asen.commons.core.meta.entity.EntityObject;
import com.asen.commons.core.meta.entity.FieldObject;
import com.asen.commons.core.meta.loader.EntityObjectLoader;
import com.asen.commons.utils.BaseAssert;
import com.asen.commons.utils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * 基础DAO
 *
 * @author Gary
 * @version 1.0
 * @date 2018-11-17
 */
@Component("dao")
public class BaseDao implements Dao {

    @Autowired
    private Jdbc jdbc;

    @Override
    public <T> int add(Class<T> modelType, T model) throws Exception {
        InsertBuilder builder = new InsertBuilder(modelType);
        builder.build(model);
        return getJdbc().update(builder);
    }

    @Override
    public <T> int update(Class<T> modelType, T model) throws Exception {
        FieldObject fo = getFieldObject(modelType, "id");
        BaseAssert.notNull(fo, "不支持没有id属性的model");
        return updateBy(modelType, model, "id");
    }

    @Override
    public <T> int updateBy(Class<T> modelType, T model, String... whereFields) throws Exception {
        return updatePartialBy(modelType, model, null, whereFields);
    }

    @Override
    public <T> int updateBy(Class<T> modelType, T model, Condition condition) throws Exception {
        UpdateBuilder builder = new UpdateBuilder(modelType);
        builder.build(model, condition);
        return getJdbc().update(builder);
    }

    @Override
    public <T> int updatePartial(Class<T> modelType, T model, String... partialFields) throws Exception {
        FieldObject fo = getFieldObject(modelType, "id");
        BaseAssert.notNull(fo, "不支持没有id属性的model");
        return updatePartialBy(modelType, model, partialFields, "id");
    }

    @Override
    public <T> int updatePartialBy(Class<T> modelType, T model, String[] partialFields, String... whereFields) throws Exception {
        return updatePartialBy(modelType, model, partialFields, whereFields, null);
    }

    @Override
    public <T> int updatePartialBy(Class<T> modelType, T model, String[] partialFields, String[] whereFields, String... ignoreFields) throws Exception {
        UpdateBuilder builder = new UpdateBuilder(modelType);
        builder.buildPartial(model, partialFields, whereFields, ignoreFields);
        return getJdbc().update(builder);
    }

    @Override
    public <T> int delete(Class<T> modelType, Long id) throws Exception {
        if (id == null || id == 0L) {
            return 0;
        }

        // 忽略没有ID或isDeleted
        if (!getEntity(modelType).hasField("id") || !getEntity(modelType).hasField("isDeleted")) {
            return 0;
        }

        // 物理删除
        T model = BeanUtils.instantiateClass(modelType);
        getEntity(modelType).setSimpleValue(model, "id", id);
        BaseAssert.notNull(model, "model不能为空");
        DeleteBuilder builder = new DeleteBuilder(modelType);
        builder.build(model, "id");
        return getJdbc().update(builder);
    }

    @Override
    public <T> int delete(Class<T> modelType, T model) throws Exception {
        checkIdValue(modelType, model);
        return deleteBy(modelType, model, "id");
    }

    @Override
    public <T> int deleteBy(Class<T> modelType, T model, String... whereFields) throws Exception {
        BaseAssert.notNull(model, "model不能为空");
        DeleteBuilder builder = new DeleteBuilder(modelType);
        builder.build(model, whereFields);
        return getJdbc().update(builder);
    }

    @Override
    public <T> int deleteBy(Class<T> modelType, Condition condition) throws Exception {
        BaseAssert.notNull(modelType, "model不能为空");
        DeleteBuilder builder = new DeleteBuilder(modelType);
        builder.build(condition);
        return getJdbc().update(builder);
    }

    @Override
    public <T> T getValue(Class<T> modelType, Long id) throws Exception {
        BaseAssert.check(id != null && id > 0L, "id不能为空");
        Condition condition = new Condition();
        condition.equal("id", id);
        condition.limit(1);

        List<T> list = getList(modelType, condition);
        T model = null;
        if (list.size() > 0) {
            model = list.get(0);
        }

        return model;
    }

    @Override
    public <T> List<T> getAll(Class<T> modelType) throws Exception {
        QueryBuilder builder = new QueryBuilder(modelType);
        builder.build();
        BaseResultSetExtractor<T> extractor = new BaseResultSetExtractor<T>(modelType);
        List<T> list = getJdbc().query(builder, extractor);
        return list;
    }

    @Override
    public <T> List<T> getAll(Class<T> modelType, int pageNum, int pageSize) throws Exception {
        QueryBuilder builder = new QueryBuilder(modelType);

        Condition condition = new Condition();
        condition.setPage(true);
        condition.setPageNum(pageNum);
        condition.setPageSize(pageSize);
        builder.build(condition);

        BaseResultSetExtractor<T> extractor = new BaseResultSetExtractor<T>(modelType);
        List<T> list = getJdbc().query(builder, extractor);

        return list;
    }

    @Override
    public <T> List<T> getList(Class<T> modelType, Condition condition) throws Exception {
        BaseAssert.notNull(condition, "参数condition不能为空");

        QueryBuilder builder = new QueryBuilder(modelType);
        builder.build(condition);

        BaseResultSetExtractor<T> extractor = new BaseResultSetExtractor<T>(modelType);
        List<T> list = getJdbc().query(builder, extractor);

        return list;
    }

    @Override
    public <T> int getCount(Class<T> modelType) throws Exception {
        SqlContext context = new SqlContext(modelType);
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT COUNT(*) FROM ");
        sql.append(context.getMainTable());
        if (getEntity(modelType).hasField("isDeleted")) {
            sql.append(" `is_deleted`=0");
        }
        SqlRowSet rowSet = getJdbc().queryForRowSet(sql.toString());
        int count = 0;
        if (rowSet.next()) {
            count = rowSet.getInt(1);
        }
        return count;
    }

    @Override
    public <T> int getCount(Class<T> modelType, Condition condition) throws Exception {
        BaseAssert.notNull(condition, "参数condition不能为空");

        boolean isPage = condition.isPage();
        QueryBuilder builder = new QueryBuilder(modelType);
        condition.setPage(false);
        builder.build(condition);
        condition.setPage(isPage);
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT COUNT(*) FROM (");
        sql.append(builder.getSql());
        sql.append(") _t");

        SqlRowSet rowSet = null;
        if (builder.getParams().isEmpty()) {
            rowSet = getJdbc().queryForRowSet(sql.toString());
        } else {
            rowSet = getJdbc().queryForRowSet(sql.toString(), builder.getParams());
        }

        int count = 0;
        if (rowSet.next()) {
            count = rowSet.getInt(1);
        }

        return count;
    }

    @Override
    public int execSql(String sql) throws Exception {
        return getJdbc().update(sql);
    }

    @Override
    public List<Map<String, Object>> query(String sql) throws Exception {
        return getJdbc().query(sql);
    }

    private <T> void checkIdValue(Class<T> modelType, T model) throws Exception {
        FieldObject fo = getFieldObject(modelType, "id");
        BaseAssert.notNull(fo, "不支持没有id属性的model");
        Long id = (Long) fo.getValue(model);
        BaseAssert.check(id != null && id > 0L, "不支持没有id属性的model");
    }

    private <T> Object getFieldValue(Class<T> modelType, T model, String fieldName) throws Exception {
        FieldObject fo = getFieldObject(modelType, fieldName);
        return fo == null ? null : fo.getValue(model);
    }

    private <T> FieldObject getFieldObject(Class<T> modelType, String fieldName) {
        return getEntity(modelType).getFieldObject(fieldName);
    }

    private <T> EntityObject getEntity(Class<T> modelType) {
        EntityObject entityObject = EntityObjectLoader.getInstance().load(modelType);
        return entityObject;
    }

    @Override
    public Jdbc getJdbc() {
        if (jdbc == null) {
            jdbc = JdbcFactory.createJdbc();
        }
        return jdbc;
    }

    @Override
    public void setJdbc(Jdbc jdbc) {
        this.jdbc = jdbc;
    }

}
